
/*-------------------------------------------------------------------------
 *
 * bufmask.c
 *	  缓冲区掩码的例程。用于掩盖在生成WAL时和应用WAL时可能不同的页面中的某些位。
 *
 * Portions Copyright (c) 2016-2022, PostgreSQL Global Development Group
 *
 * 包含掩盖页面所需的常用例程。
 *
 * IDENTIFICATION
 *	  src/backend/access/common/bufmask.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/bufmask.h"

/*
 * mask_page_lsn_and_checksum
 *
 * 在一致性检查中，被比较的两个页面的 LSN 可能会因为在生成 WAL 时的并发操作和在应用 WAL 时页面的状态而不同。此外，屏蔽校验和，因为在页面上屏蔽任何其他内容意味着校验和也不会匹配。
 */
void mask_page_lsn_and_checksum(Page fc_page)
{
	PageHeader	fc_phdr = (PageHeader) fc_page;

	PageXLogRecPtrSet(fc_phdr->pd_lsn, (uint64) MASK_MARKER);
	fc_phdr->pd_checksum = MASK_MARKER;
}

/*
 * mask_page_hint_bits
 *
 * 屏蔽 PageHeader 中的提示位。我们希望忽略提示位的差异，因为它们可以在不发出任何 WAL 的情况下设置。
 */
void mask_page_hint_bits(Page fc_page)
{
	PageHeader	fc_phdr = (PageHeader) fc_page;

	/* 忽略 prune_xid（它像一个提示位） */
	fc_phdr->pd_prune_xid = MASK_MARKER;

	/* 忽略 PD_PAGE_FULL 和 PD_HAS_FREE_LINES 标志，它们只是提示。 */
	PageClearFull(fc_page);
	PageClearHasFreeLinePointers(fc_page);

	/*
	 * 在重播期间，如果页面 LSN 已经超过我们的 XLOG 记录的 LSN，
	 * 我们不会将页面标记为全可见。有关详细信息，请参见 heap_xlog_visible()。
	 */
	PageClearAllVisible(fc_page);
}

/*
 * mask_unused_space
 *
 * 屏蔽页面中 pd_lower 和 pd_upper 之间的未使用空间。
 */
void mask_unused_space(Page fc_page)
{
	int			fc_pd_lower = ((PageHeader) fc_page)->pd_lower;
	int			fc_pd_upper = ((PageHeader) fc_page)->pd_upper;
	int			fc_pd_special = ((PageHeader) fc_page)->pd_special;

	/* 整体检查 */
	if (fc_pd_lower > fc_pd_upper || fc_pd_special < fc_pd_upper ||
		fc_pd_lower < SizeOfPageHeaderData || fc_pd_special > BLCKSZ)
	{
		elog(ERROR, "invalid page pd_lower %u pd_upper %u pd_special %u",
			 fc_pd_lower, fc_pd_upper, fc_pd_special);
	}

	memset(fc_page + fc_pd_lower, MASK_MARKER, fc_pd_upper - fc_pd_lower);
}

/*
 * mask_lp_flags
 *
 * 在某些索引访问方法中，行指针标志可以在主节点上被修改，而不发出任何 WAL 记录。
 */
void mask_lp_flags(Page fc_page)
{
	OffsetNumber fc_offnum,
				fc_maxoff;

	fc_maxoff = PageGetMaxOffsetNumber(fc_page);
	for (fc_offnum = FirstOffsetNumber;
		 fc_offnum <= fc_maxoff;
		 fc_offnum = OffsetNumberNext(fc_offnum))
	{
		ItemId		fc_itemId = PageGetItemId(fc_page, fc_offnum);

		if (ItemIdIsUsed(fc_itemId))
			fc_itemId->lp_flags = LP_UNUSED;
	}
}

/*
 * mask_page_content
 *
 * 在某些索引访问方法中，已删除页面的内容几乎需要被完全忽略。
 */
void mask_page_content(Page fc_page)
{
	/* 屏蔽页面内容 */
	memset(fc_page + SizeOfPageHeaderData, MASK_MARKER,
		   BLCKSZ - SizeOfPageHeaderData);

	/* 屏蔽 pd_lower 和 pd_upper */
	memset(&((PageHeader) fc_page)->pd_lower, MASK_MARKER,
		   sizeof(uint16));
	memset(&((PageHeader) fc_page)->pd_upper, MASK_MARKER,
		   sizeof(uint16));
}
